package models

import (
	"errors"
	"go-admin-official/guard"
	"go-admin-official/modules/config"
	"go-admin-official/modules/database"
	"go-admin-official/modules/pay"
)

type OrderModel struct {
	Base

	Id           int64  `json:"id"`
	OrderNo      string `json:"order_no"`
	ProductId    int64  `json:"product_id"`
	UserId       int64  `json:"user_id"`
	Amount       int64  `json:"amount"`
	State        int64  `json:"state"`
	Channel      int64  `json:"channel"`
	Result       int64  `json:"result"`
	Type         int64  `json:"type"`
	NotifyResult string `json:"notify_result"`
	Remark       string `json:"remark"`
	OutTradeNo   string `json:"out_trade_no"`
	TradeNo      string `json:"trade_no"`
	MerchantId   int64  `json:"merchant_id"`
	Check        int64  `json:"check"`
	CreatedAt    string `json:"created_at"`
	UpdatedAt    string `json:"updated_at"`
}

func Order() OrderModel {
	return OrderModel{Base: Base{Table: "orders"}}
}

func (u OrderModel) WithTx(tx *database.SqlTx) OrderModel {
	u.Tx = tx
	return u
}

func (u OrderModel) WithID(id int64) OrderModel {
	u.Id = id
	return u
}

func (u OrderModel) Find(id interface{}) OrderModel {
	item, _ := database.Table(u.Table).Find(id)
	return u.MapToModel(item)
}

func (u OrderModel) FindByOrderNo(no string) OrderModel {
	item, _ := database.Table(u.Table).Where("order_no", "=", no).First()
	return u.MapToModel(item)
}

func (u OrderModel) Processed() bool {
	return u.State != OrderStateSubmit && u.State != OrderStateInit
}

func (u OrderModel) PaySuccess() bool {
	return u.State == OrderStatePaySuccess
}

func (u OrderModel) PayFail() bool {
	return u.State == OrderStatePayError
}

func (u OrderModel) IsEmpty() bool {
	return u.Id == int64(0)
}

func (u OrderModel) HasProceed() bool {
	return u.State != OrderStateSubmit
}

const (
	OrderStateInit       = int64(0) // 新建但未提交到支付商户平台
	OrderStateSubmit     = int64(1) // 提交到支付商户平台
	OrderStatePaySuccess = int64(2) // 支付成功
	OrderStatePayError   = int64(3) // 支付失败

	OrderCheckNoYet = int64(0) // 校验完成
	OrderChecked    = int64(1)
)

func (u OrderModel) New(param guard.CreateOrderParam, userID int64) (OrderModel, GoodsModel, error) {

	// TODO: 获取商品价格（折扣/优惠券/会员价）
	good, err := Goods().FindByUUID(param.ProductUUID)

	if err != nil {
		return Order(), good, err
	}

	if good.IsEmpty() {
		return Order(), good, errors.New("wrong parameter")
	}

	mchID := ""

	if param.IsWechatPay() {
		mchID = config.Get().WxPayMchID
	}

	if param.IsAlipay() {
		mchID = config.Get().WxPayMchID
	}

	no := pay.GenerateOrderNum()
	id, err := database.Table(u.Table).Insert(database.H{
		"order_no":    no,
		"amount":      good.Price,
		"product_id":  good.Id,
		"result":      0,
		"user_id":     userID,
		"state":       OrderStateInit,
		"check":       OrderCheckNoYet,
		"channel":     param.Channel, // 支付渠道：微信/支付宝
		"type":        param.Type,
		"merchant_id": mchID, // TODO: 动态获取正在使用的商户ID
	})
	if err != nil {
		return Order(), good, err
	}
	order := Order().WithID(id)
	order.OrderNo = no
	return order, good, nil
}

func (u OrderModel) UpdateSubmit() error {
	_, err := database.SetTx(u.Tx).Table(u.Table).
		Where("id", "=", u.Id).
		Update(database.H{
			"state": OrderStateSubmit,
		})
	return err
}

func (u OrderModel) UpdateSuccess(msg, outTradeNo, tradeNo string) error {
	_, err := database.SetTx(u.Tx).Table(u.Table).
		Where("id", "=", u.Id).
		Update(database.H{
			"state":         OrderStatePaySuccess,
			"result":        1,
			"notify_result": msg,
			"out_trade_no":  outTradeNo,
			"trade_no":      tradeNo,
		})
	return err
}

func (u OrderModel) UpdateFail() error {
	_, err := database.SetTx(u.Tx).Table(u.Table).
		Where("id", "=", u.Id).
		Update(database.H{
			"state": OrderStatePayError,
		})
	return err
}

func (u OrderModel) MapToModel(m map[string]interface{}) OrderModel {
	u.Id, _ = m["id"].(int64)
	u.OrderNo, _ = m["order_no"].(string)
	u.ProductId, _ = m["product_id"].(int64)
	u.UserId, _ = m["user_id"].(int64)
	u.Amount, _ = m["amount"].(int64)
	u.State, _ = m["state"].(int64)
	u.Channel, _ = m["channel"].(int64)
	u.Result, _ = m["result"].(int64)
	u.Type, _ = m["type"].(int64)
	u.NotifyResult, _ = m["notify_result"].(string)
	u.Remark, _ = m["remark"].(string)
	u.OutTradeNo, _ = m["out_trade_no"].(string)
	u.TradeNo, _ = m["trade_no"].(string)
	u.MerchantId, _ = m["merchant_id"].(int64)
	u.Check, _ = m["check"].(int64)
	u.CreatedAt, _ = m["created_at"].(string)
	u.UpdatedAt, _ = m["updated_at"].(string)
	return u
}
